#include "Connection.h"
#include <unistd.h>
#include <cstring>
#include <unistd.h>
#include <sys/syscall.h>
#include "Log.h"

Connection::Connection(EventLoop *loop, std::unique_ptr<Socket> clientsock)
    : m_loop(loop), m_clientsock(std::move(clientsock)), m_disconnect(false), m_clientchannel(new Channel(m_loop, m_clientsock->fd()))
{
    // m_clientchannel = new Channel(m_loop, m_clientsock->fd());
    m_clientchannel->set_read_callback(std::bind(&Connection::on_message, this));
    m_clientchannel->set_close_callback(std::bind(&Connection::close_callback, this));
    m_clientchannel->set_error_callback(std::bind(&Connection::error_callback, this));
    m_clientchannel->set_write_callback(std::bind(&Connection::write_callback, this));
    m_clientchannel->use_et();
    //m_clientchannel->enable_reading();
}

Connection::~Connection()
{
    //LOG(INFO)<<"connection已析构";
}

std::string Connection::ip()
{
    return m_clientsock->ip();
}
uint16_t Connection::port()
{
    return m_clientsock->port();
}

int Connection::fd()
{
    return m_clientsock->fd();
}

void Connection::on_message()
{
    char buffer[1024];
    while (true)
    {
        bzero(buffer, sizeof(buffer));
        ssize_t nread = read(fd(), buffer, sizeof(buffer));
        // 成功的读取到了数据。
        if (nread > 0)
        {
            //接收报文到缓冲区
            m_inputbuffer.append(buffer, nread);
        }
        // 读取数据的时候被信号中断，继续读取。
        else if (nread == -1 && errno == EINTR)
        {
            continue;
        }
        // 全部的数据已读取完毕。
        else if (nread == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
        {
            std::string message;
            while (true)
            {
                if(!m_inputbuffer.pick_message(message))
                    break;

                m_lasttime = Timestamp::now();
                //LOG(INFO)<<"time:"<<m_lasttime.to_string();
                if(m_on_message_callback)
                    m_on_message_callback(shared_from_this(), message);
                else
                {
                    LOG(INFO)<<"m_on_message_callback2.fd("<<fd()<<")";
                    exit(4);
                }
            }
            break;
        }
        // 客户端连接已断开。
        else if (nread == 0)
        {
            //LOG(INFO)<<"close_callback3";
            close_callback();
            break;
        }
    }
}

void Connection::close_callback()
{
    m_disconnect = true;
    m_clientchannel->remove();

    m_close_callback(shared_from_this());   

}
void Connection::error_callback()
{
    m_disconnect = true;
    m_clientchannel->remove();

    m_error_callback(shared_from_this());
}
void Connection::write_callback()
{
    // todo ET模式下，这样写代码可能导致没发送完吧，如果没发送完怎么办?
    int size = ::send(fd(), m_outputbuffer.data(), m_outputbuffer.size(), 0);
    if (size > 0)
        m_outputbuffer.erase(0, size);
    // 如果发送缓冲区中没有数据了，表示数据已发送完成，不再关注写事件。
    // 防止在LT模式下，写事件一直触发
    if (m_outputbuffer.size() == 0)
    {
        m_clientchannel->disable_writing();
        
        m_send_complete_callback(shared_from_this());
    }
}
void Connection::set_close_callback(std::function<void(ConnectionPtr)> fn)
{
    m_close_callback = fn;
}
void Connection::set_error_callback(std::function<void(ConnectionPtr)> fn)
{
    m_error_callback = fn;
}

void Connection::set_on_message_callback(std::function<void(ConnectionPtr, std::string &)> fn)
{
    m_on_message_callback = fn;
}

void Connection::send(const char *data, size_t size)
{
    if (m_disconnect)
    {
        //LOG(INFO)<<"客户端已断开，send直接返回.";
        return;
    }

    //如果该函数在IO线程中，直接发送
    if (m_loop->is_in_loop_thread())
    {
        //LOG(INFO)<<"send() 在事件循环的线程中。";
        send_in_loop(data, size);
    }
    //如果该函数在WORK线程中，把发送数据的操作交给IO线程执行
    else
    {
        //LOG(INFO)<<"send() 不在事件循环的线程中。";
        //LOG(INFO)<<"send():"<<data;
        m_loop->queue_in_loop(std::bind(&Connection::send_string_in_loop, this, std::string(data,size)));
    }
}

void Connection::set_send_complete_callback(std::function<void(ConnectionPtr)> fn)
{
    m_send_complete_callback = fn;
}

void Connection::send_string_in_loop(std::string data)
{
    // todo 问题所在
    //LOG(INFO)<<"send_in_loop:"<<data;
    m_outputbuffer.append_by_sep(data.c_str(), data.size());
    m_clientchannel->enable_writing();
    //send_directly();
}

void Connection::send_in_loop(const char *data, size_t size)
{
    // todo 问题所在
    //LOG(INFO)<<"send_in_loop:"<<data;
    m_outputbuffer.append_by_sep(data, size);
    m_clientchannel->enable_writing();
    //send_directly();
}

bool Connection::is_timeout(time_t now, time_t threshold)
{
    return now - m_lasttime.to_int() > threshold;
}

//todo 修改的bug
void Connection::clientchannel_enableread()
{
    m_clientchannel->enable_reading();
}

void Connection::send_directly()
{
    int size = ::send(fd(), m_outputbuffer.data(), m_outputbuffer.size(), 0);
    if (size > 0)
        m_outputbuffer.erase(0, size);
}